package studia.figlewicz.math.library;

import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class ModelDefaultCurve extends Model {

	public final static String[] nazwyZmiennychObjasniajacych = {
		ModelDefaultCurve.ZMIENNA_OBJASNIAJACA_STOPA_PROCENTOWA,
		ModelDefaultCurve.ZMIENNA_OBJASNIAJACA_KRZYWA_DEAULTU
	};
	public final static String ZMIENNA_OBJASNIAJACA_STOPA_PROCENTOWA = Stale.MODEL_DEFAULT_CURVE_ZM_IR;
	public final static String ZMIENNA_OBJASNIAJACA_KRZYWA_DEAULTU = Stale.MODEL_DEFAULT_CURVE_ZM_DEFAULT_RATE;
	public final static String[] nazwyZmiennychObjasnianych = {
		ModelDefaultCurve.ZMIENNA_OBJASNIANA_PRAWDOPODOBIENSTWO_NIEWYPLACALNOSCI
	};
	public final static String ZMIENNA_OBJASNIANA_PRAWDOPODOBIENSTWO_NIEWYPLACALNOSCI = Stale.MODEL_DEFAULT_CURVE_WYNIK_PRAWDOPODOBIENSTWO_NIEWYPLACALNOSCI;
	
	private MetodaInterpolacji interpolacja;
	
	
	// konstruktory
	public ModelDefaultCurve(MetodaInterpolacji interpolacja) {
		super();
		for (String zm : nazwyZmiennychObjasniajacych) {
			zmienneObjasniajace.put(zm, null);
		}
		this.interpolacja = interpolacja;
	}
	
	
	// gettery i settery
	public MetodaInterpolacji getInterpolacja() {
		return interpolacja;
	}
	public void setInterpolacja(MetodaInterpolacji interpolacja) {
		this.interpolacja = interpolacja;
	}
	@Override
	public String[] getNazwyZmiennychObjasnianych() {
		return nazwyZmiennychObjasnianych;
	}
	@Override
	public String[] getNazwyZmiennychObjasniajacych() {
		return nazwyZmiennychObjasnianych;
	}
	
	
	// metody
	@Override
	public Map<String, TrajektoriaProcesu> utworzBuforWynikuProjekcji() {
		Map<String, TrajektoriaProcesu> resoult = new HashMap<String, TrajektoriaProcesu>();
		for (String zm : nazwyZmiennychObjasnianych) {
			resoult.put(zm, new TrajektoriaProcesu());
		}
		return resoult;
		
	}
	@Override
	public void inicjalucujProjekcje(Date poczatekSymulacji) {
		this.poczatekProjekcji = poczatekSymulacji;
	}
	public Map<String, Double> wyznaczKrokProjekcji(Date dzienProjekcji,  Map<String, TrajektoriaProcesu> dotychczasoweTrajektorie) {
		Map<String, Double> resoult = new HashMap<String, Double>();
		Double value = null;
		ZmiennaObjasniajaca stopaProcentowa = zmienneObjasniajace.get(ZMIENNA_OBJASNIAJACA_STOPA_PROCENTOWA);
		ZmiennaObjasniajaca prawdopodobienstwoDefaultu = zmienneObjasniajace.get(ZMIENNA_OBJASNIAJACA_KRZYWA_DEAULTU);
		
		if (stopaProcentowa != null && prawdopodobienstwoDefaultu != null) {
			TrajektoriaProcesu krzywaZerokuponowa = dotychczasoweTrajektorie.get(ZMIENNA_OBJASNIANA_PRAWDOPODOBIENSTWO_NIEWYPLACALNOSCI);
			
			Date poczatek = null;
			if (krzywaZerokuponowa.getPukntySymulacji().size() == 0) {
				poczatek = this.poczatekProjekcji;
			}
			else {
				PunktTrajektorii ostatniPunkt = krzywaZerokuponowa.koniecTrajektorii();
				poczatek = ostatniPunkt.getData();
			}

			double r = integral(stopaProcentowa, poczatek, dzienProjekcji,1);
			double pDafault = integral(prawdopodobienstwoDefaultu, poczatek, dzienProjekcji,1);

			double dr = pDafault / (1 + r);
			value = new Double(dr);
		}

		resoult.put(ZMIENNA_OBJASNIANA_PRAWDOPODOBIENSTWO_NIEWYPLACALNOSCI, value);
		
		return resoult;
	}

	
	// metody prywatne
	@Override
	protected boolean isObjasniajaca(String nazwa) {
		boolean resoult = false;
		for (String zm : nazwyZmiennychObjasniajacych) {
			if (zm.equals(nazwa)) {
				resoult = true;
				break;
			}
		}
		
		return resoult;
	}
	@Override	
	protected boolean isObjasniana(String nazwa) {
		boolean resoult = false;
		for (String zm : nazwyZmiennychObjasnianych) {
			if (zm.equals(nazwa)) {
				resoult = true;
				break;
			}
		}
		
		return resoult;
	}
	private double integral(ZmiennaObjasniajaca zmienna, Date poczatek, Date koniec, int potega) {
		double resoult = 0;
		
		LinkedHashMap<Date, Double> punkty = zmienna.getPunkty();
		
		Double val1 = Utils.wartoscWygladzona(punkty, poczatek, interpolacja);
		Double val2 = Utils.wartoscWygladzona(punkty, koniec, interpolacja);
		double podsatwa = Utils.getYearFractionStandard(poczatek,koniec);
		
		if (potega > 1) {
			double srednia = 1/2 * (val1.doubleValue() + val2.doubleValue());
			double oldval1 = val1.doubleValue();
			double oldval2 = val1.doubleValue();
			for (int i=1; i<potega; i++) {
				val1 = val1.doubleValue() * oldval1;
				val2 = val2.doubleValue() * oldval2;
			}
			if (val1.doubleValue() < val2.doubleValue()) {
				resoult = podsatwa * 1/2 * (val1.doubleValue() + srednia);
				resoult = resoult + podsatwa * 1/2 * (srednia + val2.doubleValue());
			}
			else {
				resoult = podsatwa * 1/2 * (val2.doubleValue() + srednia);
				resoult = resoult + podsatwa * 1/2 * (srednia + val1.doubleValue());
			}
		}
		else
			resoult = podsatwa * 1/2 * (val1.doubleValue() + val2.doubleValue());
		
		return resoult;
	}
	
	
	
}
